<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Layoutmanagement in PyQt4</title>
<link rel="stylesheet" href="../format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="PyQt, PyQt4, layout management, tutorial, python, Linux">
<meta nam="description" content="Layoutmanagement in PyQt4">
<meta name="language" content="de">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">
<meta name="translation" content="manuel stein">
</head>

<body>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href=".." title="Home">Contents</a>


<h1>Layoutmanagement in PyQt4</h1>

<p>
Ein wichtiges Thema beim Programmieren grafischer Oberflächen ist das Layoutmanagement, 
mittels dessen wir Widgets im Fenster platzieren. Das Management kann auf zwei Wege von
 statten gehen: Durch <strong>absolutes Positionieren</strong> oder <strong>Layout-Klassen</strong>.
</p>

<h3>Absolutes Positionieren</h3>

<p>
Der Programmierer legt die Position und die Größe jedes Widgets in Pixeln fest. 
Wenn Sie absolutes Positionieren anwenden, müssen Sie zuvor einige Dinge verstehen.
</p>

<ul>
<li>Die Größe und die Position eines Widget ändern sich nicht, wenn Sie die Größe eines Fensters ändern.</li>
<li>Anwendungen können sich in ihrem Aussehen abhängig von der Plattform unterscheiden. </li>
<li>Veränderte Schriften können das Layout Ihrer Anwendung zerschießen.</li>
<li>Entscheiden Sie sich, Ihr Layout zu ändern, müssen Sie es vollständig neu erstellen, was lästig und zeitraubend ist.</li>
</ul>

<pre class="code">
#!/usr/bin/python

# absolute.py

import sys
from PyQt4 import QtGui


class Absolute(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setWindowTitle('Communication')

        label = QtGui.QLabel('Couldn\'t', self)
        label.move(15, 10)

        label = QtGui.QLabel('care', self)
        label.move(35, 40)

        label = QtGui.QLabel('less', self)
        label.move(55, 65)

        label = QtGui.QLabel('And', self)
        label.move(115, 65)

        label = QtGui.QLabel('then', self)
        label.move(135, 45)

        label = QtGui.QLabel('you', self)
        label.move(115, 25)

        label = QtGui.QLabel('kissed', self)
        label.move(145, 10)

        label = QtGui.QLabel('me', self)
        label.move(215, 10)

        self.resize(250, 150)

app = QtGui.QApplication(sys.argv)
qb = Absolute()
qb.show()
sys.exit(app.exec_())
</pre>

<p>
Wir rufen einfach die <em>move()</em>-Methode zur Platzierung unserer Widgets auf, 
in diesem Fall QLabel. Wir positionieren sie, indem wir die x- und y-Koordinaten 
übergeben. Der Nullpunkt des Koordinatensystems befindet sich in der linken oberen 
Ecke. Der x-Wert wächst von links nach rechts, der y-Wert von oben nach unten.
</p>

<img src="../images/absolute.jpg" alt="Absolutes Positionieren">
<p class="figure">Abbildung: Absolutes Positionieren</p>

<h3>Box-Layout</h3>

<p>
Das Layoutmanagement mit Hilfe von Layout-Klassen is erheblich flexibler und 
praktischer. Dieser Weg, Widgets in einem Fenster zu platzieren, ist der 
grundsätzlich vorzuziehende. Die grundlegenden Layout-Klassen 
sind <strong>QHBoxLayout</strong> und <strong>QVBoxLayout</strong>. 
Sie reihen Widgets horizontal <acronym title="zum Beispiel">z.B.</acronym> 
vertikal aneinander.
</p>

<p>
Stellen Sie sich vor, wir wollten zwei Knöpfe in der rechten unteren 
Ecke platzieren. Um ein solches Layout zu erzeugen, werden wir eine 
horizontale und eine vertikale Box verwenden. Für die erforderliche 
Fläche fügen wir einen <strong>Ausdehnungsfaktor</strong> hinzu.
</p>

<pre class="code">
#!/usr/bin/python

# boxlayout.py

import sys
from PyQt4 import QtGui


class BoxLayout(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setWindowTitle('box layout')

        ok = QtGui.QPushButton("OK")
        cancel = QtGui.QPushButton("Cancel")

        hbox = QtGui.QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(ok)
        hbox.addWidget(cancel)

        vbox = QtGui.QVBoxLayout()
        vbox.addStretch(1)
        vbox.addLayout(hbox)

        self.setLayout(vbox)

        self.resize(300, 150)

app = QtGui.QApplication(sys.argv)
qb = BoxLayout()
qb.show()
sys.exit(app.exec_())
</pre>

<pre class="explanation">
 ok = QtGui.QPushButton("OK")
 cancel = QtGui.QPushButton("Cancel")
</pre>

<p>
Hier erzeugen wir zwei Druckknöpfe.
</p>

<pre class="explanation">
 hbox = QtGui.QHBoxLayout()
 hbox.addStretch(1)
 hbox.addWidget(ok)
 hbox.addWidget(cancel)
</pre>

<p>
Wir erzeugen ein horizontales Box-Layout, fügen den Ausdehnungsfaktor 
(<em>stretch factor</em>) und beide Knöpfe hinzu.
</p>

<pre class="explanation">
 vbox = QtGui.QVBoxLayout()
 vbox.addStretch(1)
 vbox.addLayout(hbox)
</pre>

<p>
Zur Erzeugung des gewünschten Layouts packen wir ein horizontales Layout in ein vertikales.
</p>

<pre class="explanation">
 self.setLayout(vbox)
</pre>

<p>
Abschließend  bestimmen wir das Hauptlayout des Fensters.
</p>

<img src="../images/boxlayout.jpg" alt="Box-Layout">
<p class="figure">Abbildung: Box-Layout</p>

<h3>QGridLayout</h3>

<p>
Die universellste Layout-Klasse ist das Rasterlayout, welches die Fläche in 
Reihen und Spalten einteilt. Um ein Rasterlayout zu erzeugen, verwenden wir 
die <strong>QGridLayout</strong>-Klasse.
</p>

<pre class="code">
#!/usr/bin/python

# gridlayout.py

import sys
from PyQt4 import QtGui


class GridLayout(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setWindowTitle('grid layout')

        names = ['Cls', 'Bck', '', 'Close', '7', '8', '9', '/',
            '4', '5', '6', '*', '1', '2', '3', '-',
            '0', '.', '=', '+']

        grid = QtGui.QGridLayout()

        j = 0
        pos = [(0, 0), (0, 1), (0, 2), (0, 3),
                (1, 0), (1, 1), (1, 2), (1, 3),
                (2, 0), (2, 1), (2, 2), (2, 3),
                (3, 0), (3, 1), (3, 2), (3, 3 ),
                (4, 0), (4, 1), (4, 2), (4, 3)]

        for i in names:
            button = QtGui.QPushButton(i)
            if j == 2:
                grid.addWidget(QtGui.QLabel(''), 0, 2)
            else: grid.addWidget(button, pos[j][0], pos[j][1])
            j = j + 1

        self.setLayout(grid)



app = QtGui.QApplication(sys.argv)
qb = GridLayout()
qb.show()
sys.exit(app.exec_())
</pre>

<p>
In unserem Beispiel erzeugen wir ein Raster mit Knöpfen. Um ein Feld zu füllen, 
fügen wir ein QLabel-Widget ein.
</p>

<pre class="explanation">
 grid = QtGui.QGridLayout()
</pre>

<p>
Wir erzeugen hier ein Rasterlayout.
</p>

<pre class="explanation">
 if j == 2:
     grid.addWidget(QtGui.QLabel(''), 0, 2)
 else: grid.addWidget(button, pos[j][0], pos[j][1])
</pre>

<p>
Um ein Widget einem Raster hinzuzufügen, rufen wir die <em>addWidget()</em>-Methode auf. 
Ihre Argumente sind das Widget, dieNummer der Reihe und der Spalte.
</p>

<img src="../images/gridlayout.jpg" alt="Rasterlayout">
<p class="figure">Abbildung: Rasterlayout</p>

<p>
Widgets können mehrere Spalten und Reihen eines Rasters umfassen. 
Wir werden dies im folgenden Beispiel demonstrieren.
</p>

<pre class="code">
#!/usr/bin/python

# gridlayout2.py

import sys
from PyQt4 import QtGui


class GridLayout2(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setWindowTitle('grid layout')

        title = QtGui.QLabel('Title')
        author = QtGui.QLabel('Author')
        review = QtGui.QLabel('Review')

        titleEdit = QtGui.QLineEdit()
        authorEdit = QtGui.QLineEdit()
        reviewEdit = QtGui.QTextEdit()

        grid = QtGui.QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(title, 1, 0)
        grid.addWidget(titleEdit, 1, 1)

        grid.addWidget(author, 2, 0)
        grid.addWidget(authorEdit, 2, 1)

        grid.addWidget(review, 3, 0)
        grid.addWidget(reviewEdit, 3, 1, 5, 1)


        self.setLayout(grid)
        self.resize(350, 300)


app = QtGui.QApplication(sys.argv)
qb = GridLayout2()
qb.show()
sys.exit(app.exec_())
</pre>

<pre class="explanation">
 grid = QtGui.QGridLayout()
 grid.setSpacing(10)
</pre>

<p>
Wir erzeugen ein Rasterlayout und definieren den Abstand zwischen den Widgets.
</p>

<pre class="explanation">
 grid.addWidget(reviewEdit, 3, 1, 5, 1)
</pre>

<p>
Wenn wir ein Widget in ein Raster einfügen, können wir Reihen- und Spaltenspanne 
des Widgets angeben. In unserem Fall lassen wir das <em>reviewEdit</em>-Widget 
sich über 5 Reihen erstrecken.
</p>

<img src="../images/gridlayout2.jpg" alt="Rasterlayout 2" />
<p class="figure">Abbildung: Rasterlayout 2</p>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified September 23, 2007  <span class="copyright">&copy; 2007 - 2011 Jan Bodnar</span>
<span class="copyright">Translation © 2009 Manuel Stein</span>
</div>
</div>

</div> <!-- content -->
</body>
</html>

